/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package session.stateful;

import entity.StakeholderEntity;
import entity.BranchEntity;
import entity.RedemptionListEntity;
import entity.RedemptionItemEntity;
import entity.RedemptionPaymentItemEntity;
import entity.PaymentItemEntity;
import entity.ReservationEntity;
import entity.TouristAccountEntity;
import entity.TransactionsEntity;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Date;
import java.sql.Time;
import java.util.List;
import java.util.ArrayList;
import javax.ejb.LocalBean;
import javax.ejb.Stateful;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
// Additional imports
import java.util.Random;
import java.math.BigInteger;
import javax.ejb.EJB;
import util.entityhelper.ULPItemHelper;
// Import for the timer
import java.text.SimpleDateFormat;
import java.util.Calendar;
import util.entityhelper.AccumulationHelper;
import util.entityhelper.RedemptionHelper;

/**
 *
 * @author NGUYEN CONG DAT
 */
@Stateful
@LocalBean
public class LoyaltyProgramSessionBean {

    private static final String AB = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    private static Random rnd = new Random();
    @PersistenceContext
    private EntityManager entityManager;
    @EJB
    private EmailSessionBean emailSessionBean;
    //@Resource
    //private SessionContext ctx;

    public LoyaltyProgramSessionBean() {
        emailSessionBean = new EmailSessionBean();
        emailSessionBean.setUser("is3102team32@gmail.com");
        emailSessionBean.setPassword("emsongtronguocao");
    }

    public void stakeholderCreateULPItem(Long stakeholderId, RedemptionListEntity ULPItem) {
        ULPItem.setStatus("Application Pending");
        ULPItem.setDateCreated(new Date());
        entityManager.persist(ULPItem);
        StakeholderEntity stakeholder = entityManager.find(StakeholderEntity.class, stakeholderId);
        stakeholder.getRedemptionList().add(ULPItem);
        ULPItem.setStakeholder(stakeholder);
    }

    public void tCubeCreateULPItem(RedemptionListEntity ULPItem) {
        ULPItem.setStatus("Created by TCube");
        ULPItem.setDateCreated(new Date());
        entityManager.persist(ULPItem);
    }

    public void acceptULPItemApplication(RedemptionListEntity ULPItem) {
        ULPItem.setStatus("Application Successful");
        entityManager.merge(ULPItem);
    }

    public void denyULPItemApplication(RedemptionListEntity ULPItem) {
        ULPItem.setStatus("Application Rejected");
        entityManager.merge(ULPItem);
    }

    public void editULPItem(RedemptionListEntity ULPItem) {
        entityManager.merge(ULPItem);
    }

    public void voidULPItemApplication(Long ULPItemId) {
        RedemptionListEntity ULPItem = entityManager.find(RedemptionListEntity.class, ULPItemId);
        StakeholderEntity stakeholder = ULPItem.getStakeholder();
        List<RedemptionListEntity> ULPItems = stakeholder.getRedemptionList();
        ULPItems.remove(ULPItem);
        entityManager.remove(ULPItem);
        entityManager.merge(stakeholder);
    }

    public List<RedemptionListEntity> getAllULPItemApplicationList() {
        List<RedemptionListEntity> ULPItemApplications = new ArrayList<RedemptionListEntity>();
        List<RedemptionListEntity> allULPItems = this.getAllULPItems();
        for (RedemptionListEntity obj : allULPItems) {
            if (obj.getStatus().indexOf("Application") != -1) {
                ULPItemApplications.add(obj);
            }
        }
        return ULPItemApplications;
    }

    // OK
    public List<RedemptionListEntity> getULPItemApplicationListByStakeholderId(Long stakeholderId) {
        StakeholderEntity stakeholder = entityManager.find(StakeholderEntity.class, stakeholderId);
        List<RedemptionListEntity> allULPItems = stakeholder.getRedemptionList();
        List<RedemptionListEntity> ULPItemApplications = new ArrayList<RedemptionListEntity>();
        for (RedemptionListEntity obj : allULPItems) {
            if (obj.getStatus().indexOf("Application") != -1) {
                ULPItemApplications.add(obj);
            }
        }
        return ULPItemApplications;
    }

    //OK
    public List<RedemptionListEntity> getPendingULPItemApplicationList() {
        List<RedemptionListEntity> pendingApplications = new ArrayList<RedemptionListEntity>();
        List<RedemptionListEntity> allULPItems = this.getAllULPItems();
        for (RedemptionListEntity obj : allULPItems) {
            if (obj.getStatus().equalsIgnoreCase("Application Pending")) {
                pendingApplications.add(obj);
            }
        }
        return pendingApplications;
    }

    //OK
    public List<RedemptionListEntity> getPendingULPItemApplicationListByStakeholderId(Long stakeholderId) {
        StakeholderEntity stakeholder = entityManager.find(StakeholderEntity.class, stakeholderId);
        List<RedemptionListEntity> pendingApplications = new ArrayList<RedemptionListEntity>();
        List<RedemptionListEntity> allULPItems = stakeholder.getRedemptionList();
        for (RedemptionListEntity obj : allULPItems) {
            if (obj.getStatus().equalsIgnoreCase("Application Pending")) {
                pendingApplications.add(obj);
            }
        }
        return pendingApplications;
    }

    //OK
    public List<RedemptionListEntity> getAcceptedULPItemApplications() {
        List<RedemptionListEntity> acceptedApplications = new ArrayList<RedemptionListEntity>();
        List<RedemptionListEntity> allULPItems = this.getAllULPItems();
        for (RedemptionListEntity obj : allULPItems) {
            if (obj.getStatus().equalsIgnoreCase("Application Successful")) {
                acceptedApplications.add(obj);
            }
        }
        return acceptedApplications;
    }

    public List<ULPItemHelper> getAllCurrentULPItems() {
        List<ULPItemHelper> currentULPItems = new ArrayList<ULPItemHelper>();
        List<RedemptionListEntity> allULPItems = this.getAllULPItems();
        for (RedemptionListEntity obj : allULPItems) {
            if (obj.getStatus().equalsIgnoreCase("Deal is on")) {
                currentULPItems.add(new ULPItemHelper(obj, getQuantityBought(obj.getId()), getQuantityUsed(obj.getId())));
            }
        }
        return currentULPItems;
    }

    public List<RedemptionListEntity> getAllCurrentULPItemEntities() {
        List<RedemptionListEntity> currentlyOfferedULPItemList = new ArrayList<RedemptionListEntity>();
        List<RedemptionListEntity> allULPItems = this.getAllULPItems();
        for (RedemptionListEntity obj : allULPItems) {
            if (obj.getStatus().equalsIgnoreCase("Deal is on") && obj.getVisibility()== true) {
                currentlyOfferedULPItemList.add(obj);
            }
        }
        return currentlyOfferedULPItemList;
    }

    public List<ULPItemHelper> getCurrentULPItemsByStakeholderId(Long stakeholderId) {
        StakeholderEntity stakeholder = entityManager.find(StakeholderEntity.class, stakeholderId);
        List<RedemptionListEntity> allULPItems = stakeholder.getRedemptionList();
        List<ULPItemHelper> currentULPItemList = new ArrayList<ULPItemHelper>();
        for (RedemptionListEntity obj : allULPItems) {
            if (obj.getStatus().equalsIgnoreCase("Deal is on")) {
                currentULPItemList.add(new ULPItemHelper(obj, getQuantityBought(obj.getId()), getQuantityUsed(obj.getId())));
            }
        }
        return currentULPItemList;
    }

    public void setStatusForULPItem(Long ULPItemId, String status) {
        RedemptionListEntity ULPItem = entityManager.find(RedemptionListEntity.class, ULPItemId);
        ULPItem.setStatus(status);
        entityManager.merge(ULPItem);
    }

    //OK
    public List<ULPItemHelper> getExpiredULPItems() {
        List<RedemptionListEntity> allULPItems = this.getAllULPItems();
        List<ULPItemHelper> expiredULPItems = new ArrayList<ULPItemHelper>();
        for (RedemptionListEntity obj : allULPItems) {
            if (obj.getStatus().equalsIgnoreCase("Expired")) {
                expiredULPItems.add(new ULPItemHelper(obj, getQuantityBought(obj.getId()), getQuantityUsed(obj.getId())));
            }
        }
        return expiredULPItems;
    }

    // OK
    public List<ULPItemHelper> getExpiredULPItemsByStakeholderId(Long stakeholderId) {
        StakeholderEntity stakeholder = entityManager.find(StakeholderEntity.class, stakeholderId);
        List<ULPItemHelper> resultList = new ArrayList<ULPItemHelper>();
        List<RedemptionListEntity> list = stakeholder.getRedemptionList();
        for (RedemptionListEntity obj : list) {
            if (obj.getStatus().equals("Expired")) {
                resultList.add(new ULPItemHelper(obj, getQuantityBought(obj.getId()), getQuantityUsed(obj.getId())));
            }
        }
        return resultList;
    }

    //OK
    public List<RedemptionListEntity> getAllULPItems() {
        Query query = entityManager.createQuery("SELECT r FROM RedemptionListEntity r");
        return query.getResultList();
    }

    public List<RedemptionItemEntity> getRedemptionListByCustomerId(Long customerId) {
        TouristAccountEntity customer = entityManager.find(TouristAccountEntity.class, customerId);
        return customer.getRedemptionItem();
    }

    public List<AccumulationHelper> getAccumulationListByCustomerId(Long customerId) {
        System.out.println("Step 1");
        TouristAccountEntity customer = entityManager.find(TouristAccountEntity.class, customerId);
        System.out.println("Step 2");
        List<AccumulationHelper> resultList = new ArrayList<AccumulationHelper>();
        System.out.println("Step 3");
        for (ReservationEntity obj : customer.getReservation()) {
            System.out.println("Step 3*");
            if (obj.getStatus().equalsIgnoreCase("Show")) {
                resultList.add(new AccumulationHelper(obj));
            }
        }
        System.out.println("Step 5");
        return resultList;
    }

    public List<RedemptionItemEntity> redeemULPItem(Long customerId, Long ULPItemId, int quantity) {
        SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy");
        TouristAccountEntity customer = entityManager.find(TouristAccountEntity.class, customerId);
        RedemptionListEntity ULPItem = entityManager.find(RedemptionListEntity.class, ULPItemId);
        String voucherDetail = "";
        List<RedemptionItemEntity> voucherList = new ArrayList<RedemptionItemEntity>();

        for (int i = 0; i < quantity; i++) {
            RedemptionItemEntity voucher = new RedemptionItemEntity();
            voucher.setRedemptionList(ULPItem);
            voucher.setCustomer(customer);
            voucher.setDateCreated(new Date());
            voucher.setDateExpired(addMonthsToCurrentDate(voucher.getDateCreated(), ULPItem.getValidPeriod()));
            String code = "";
            while (true) {
                code = generateCode();
                Query query = entityManager.createQuery("SELECT r FROM RedemptionItemEntity r WHERE r.referenceNumber= :code");
                query.setParameter("code", code);
                if (query.getResultList().isEmpty())
                    break;
            }
            voucher.setReferenceNumber(code);
            entityManager.persist(voucher);
            ULPItem.getRedemptionItems().add(voucher);
            customer.getRedemptionItem().add(voucher);
            customer.setPoint(customer.getPoint() - ULPItem.getPointsToRedeem());
            voucherDetail = voucherDetail + "-----------------------------------------------------------------------------\n"
                    + "Voucher " + (i + 1) + ": \nVoucher name : " + ULPItem.getName()
                    + "\nReference Number: " + voucher.getReferenceNumber()
                    + "\nDate Generated: " + sdf.format(voucher.getDateCreated())
                    + "\nExpiry Date: " + sdf.format(voucher.getDateExpired())
                    + "\nNumber of Points Used: " + ULPItem.getPointsToRedeem()
                    + "\n-----------------------------------------------------------------------------\n";
            voucherList.add(voucher);
        }
        // Check if the current quantityBought has exceeded the maximum limit, if yes, then just close the deal
        if (getQuantityBought(ULPItemId) >= ULPItem.getMaxQuantity()) {
            ULPItem.setStatus("Expired");
        }
        // Email to customer informing about the vouchers redeemed
        System.out.println(customer.getTourist() == null);
        String emailMessage = "Dear " + customer.getTourist().getFirstName() + " " + customer.getTourist().getLastName()
                + ", \n\nThank you for purchasing on FoodSage.sg.\n\n"
                + "This is to acknowledge that you have just had a successful redemption on FoodSage.sg, as part of the Unified Loyalty Program.\n"
                + "Here is the detail of the vouchers generated: \n"
                + voucherDetail + "\nRemember to use your voucher(s) before the expiry date.\n"
                + "\nTotal number of points used for this redemption: " + quantity * ULPItem.getPointsToRedeem()
                + "\nIf you have free time, do not forget to visit our website to enjoy many other great deals and promotions offered on FoodSage.sg. \n"
                + "Have a nice day. \n\n FoodSage.sg. ";
        try {
            emailSessionBean.setUser("is3102team32@gmail.com");
            emailSessionBean.setPassword("emsongtronguocao");
            emailSessionBean.sendMail("is3102team32@gmail.com", customer.getTourist().getEmail(), "FoodSage.sg - Confirmation on Voucher Redemption for "
                    + customer.getTourist().getFirstName() + " " + customer.getTourist().getLastName(), emailMessage);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return voucherList;
    }

    public List<RedemptionItemEntity> getVoucherByReferenceNumber(String referenceNumber) {
        Query query = entityManager.createQuery("SELECT r FROM RedemptionItemEntity r WHERE r.referenceNumber= :referenceNumber");
        query.setParameter("referenceNumber", referenceNumber);
        return query.getResultList();
    }

    // This method declares a redeemed voucher as "used"
    public void declareVoucherAsUsed(Long branchId, Long voucherId) {
        BranchEntity branch = entityManager.find(BranchEntity.class, branchId);
        RedemptionItemEntity voucher = entityManager.find(RedemptionItemEntity.class, voucherId);
        voucher.setDateUsed(new Date());
        voucher.setBranch(branch);
        branch.getRedemptionItem().add(voucher);
        // Create payment item
        RedemptionPaymentItemEntity paymentItem = new RedemptionPaymentItemEntity();
        paymentItem.setDateCreated(new Date());
        paymentItem.setPaid(false);
        // If this ULP Item belongs to TCube (Khanh Vu check dum cho nay)
        if (voucher.getRedemptionList().getStakeholder() == null) {
            paymentItem.setAmountToStakeholder(voucher.getRedemptionList().getCostOfItem());
            paymentItem.setRedemptionItem(voucher);
            paymentItem.setExplanation("This is the amount transfered to stakeholder for the use of a redeemed voucher offered by TCube");
            paymentItem.setStakeholder(branch.getStakeholder());
        } else {
            paymentItem.setAmountToStakeholder(voucher.getRedemptionList().getCostOfItem());
            paymentItem.setRedemptionItem(voucher);
            paymentItem.setExplanation("This is the amount transfered back to stakeholder for the use of a redeemed voucher");
            paymentItem.setStakeholder(voucher.getRedemptionList().getStakeholder());
        }
        entityManager.persist(paymentItem);
        voucher.setRedemptionPaymentItem(paymentItem);
    }

    // Add months to a current date
    public Date addMonthsToCurrentDate(Date currentDate, int numberOfMonths) {
        //create Calendar instance
        Calendar cal = Calendar.getInstance();
        cal.setTime(currentDate);
        cal.add(Calendar.MONTH, numberOfMonths);
        return cal.getTime();
    }

    // This method supports the system in generating a unique reference number for a ULP item voucher
    public String generateCode() {
        String referenceNumber = "U";
        String[] dayList = {"Q", "N", "W", "J", "D", "V", "F", "Y", "R", "3",
            "E", "O", "G", "A", "X", "I", "1", "C", "S", "M",
            "Z", "L", "U", "P", "H", "B", "T", "K", "4", "2", "5"};
        String[] monthList = {"Q", "X", "5", "Y", "A", "W", "U", "F", "7", "R", "T", "B"};
        String[] yearList = {"S", "M", "D", "H", "A", "O", "F", "N", "R", "T",
                             "G", "U", "B", "I", "K", "E", "L", "P", "C", "Q",
                             "Z", "Y", "X", "W", "V"};
        String[] hourList = {"G","I","B","N","O","E","P","Q","U","W",
                             "C","X","A","R","D","H","L","J","T","V",
                             "S","F","M"};
        Date today = new Date();
        int dayIndex = today.getDay() - 1;
        int monthIndex = today.getMonth();
        int yearIndex = today.getYear() + 1900 - 2010;
        int hourIndex = today.getHours();
        referenceNumber = referenceNumber + randomString(1) + dayList[dayIndex] + randomString(1) +
                          monthList[monthIndex] + randomString(1) + yearList[(100-yearIndex)%25] + 
                          randomString(1) + hourList[hourIndex] + randomString(2);
        return referenceNumber;
    }

    private String randomString(int length) {
        StringBuilder sb = new StringBuilder(length);
        for (int i = 0; i < length; i++) {
            sb.append(AB.charAt(rnd.nextInt(AB.length())));
        }
        return sb.toString();
    }

    // This method returns the number of ULPItems that have been redeemed by customers
    public int getQuantityBought(Long ULPItemId) {
        RedemptionListEntity ULPItem = entityManager.find(RedemptionListEntity.class, ULPItemId);
        List<RedemptionItemEntity> redeemedULPItems = ULPItem.getRedemptionItems();
        if (redeemedULPItems != null) {
            return redeemedULPItems.size();
        } else {
            return 0;
        }
    }

    // This method returns the number of ULPItems that have been claimed/used by customers
    public int getQuantityUsed(Long ULPItemId) {
        int quantity = 0;
        RedemptionListEntity ULPItem = entityManager.find(RedemptionListEntity.class, ULPItemId);
        List<RedemptionItemEntity> redeemedULPItems = ULPItem.getRedemptionItems();
        for (int i = 0; redeemedULPItems != null && i < redeemedULPItems.size(); i++) {
            if (redeemedULPItems.get(i).getDateUsed() != null) {
                quantity = quantity + 1;
            }
        }
        return quantity;
    }

    public List<RedemptionItemEntity> getAllRedemptionsByStakeholderIdAndDate(Long stakeholderId, Date startDate, Date endDate) {
        Query query = entityManager.createQuery("SELECT t FROM RedemptionItemEntity t WHERE t.dateCreated >= :startDate AND t.dateCreated <= :endDate");
        query.setParameter("startDate", startDate);
        query.setParameter("endDate", endDate);
        List<RedemptionItemEntity> list = query.getResultList();
        List<RedemptionItemEntity> resultList = new ArrayList<RedemptionItemEntity>();
        for (RedemptionItemEntity r : list) {
            if (r.getDateUsed() != null && r.getBranch().getStakeholder().getId() == stakeholderId) {
                resultList.add(r);
            }
        }
        return resultList;
    }

    public List<RedemptionItemEntity> getAllRedemptionsByStakeholderId(Long stakeholderId) {
        Query query = entityManager.createQuery("SELECT t FROM RedemptionItemEntity t");
        List<RedemptionItemEntity> list = query.getResultList();
        List<RedemptionItemEntity> resultList = new ArrayList<RedemptionItemEntity>();
        for (RedemptionItemEntity r : list) {
            if (r.getDateUsed() != null && r.getBranch().getStakeholder().getId() == stakeholderId) {
                resultList.add(r);
            }
        }
        return resultList;
    }

    public List<RedemptionItemEntity> getAllRedemptionsByDate(Date startDate, Date endDate) {
        Query query = entityManager.createQuery("SELECT t FROM RedemptionItemEntity t WHERE t.dateCreated >= :startDate AND t.dateCreated <= :endDate");
        query.setParameter("startDate", startDate);
        query.setParameter("endDate", endDate);
        return query.getResultList();
    }

    public List<RedemptionItemEntity> getAllRedemptions() {
        Query query = entityManager.createQuery("SELECT t FROM RedemptionItemEntity t");
        return query.getResultList();
    }


    /*
     * Added by Khanh Vu
     * Purpose: For Web Service with redemption points
     */
    public List<RedemptionHelper> getRedemptionHelperListByTouristId(long touristId) {
        List<RedemptionItemEntity> tempList = getRedemptionListByCustomerId(touristId);

        List<RedemptionHelper> resultList = new ArrayList<RedemptionHelper>();

        for (RedemptionItemEntity redemption : tempList) {
            resultList.add(new RedemptionHelper(redemption, redemption.getRedemptionList()));
        }
        return resultList;
    }
    //End added by Khanh Vu
}